import type { MapperConfig } from "@/lib/api";
import { KeyCode, KeyCodeUppercase } from "@/lib/keyboard";

/**
 * 键盘映射器中的可行值
 */
export type KeyMapperValue = keyof typeof KeyCode;

/**
 * 键盘映射器
 *
 * 其中
 * `name` 大小写区分，
 * `rule` 中的值可以为单个 KeyMapperValue，
 * 非法值则会在转换过程中被过滤掉。
 */
export interface KeyMapper {
    name: "KeyMapper";
    rule: {
        [key: string]: KeyMapperValue[];
    };
}

/**
 * 把字符串转换为 KeyMapperValue 类型
 * @param value 要转换的值
 * @returns 转换后的值，如果转换失败则返回 undefined
 */
function asKeyMapperValue(value: string): KeyMapperValue | undefined {
    // string -> number
    const x = KeyCodeUppercase[value.toUpperCase()];
    if (x === undefined) {
        return undefined;
    }

    // number -> string
    // 这里的 toUpperCase 目的是过滤掉原始的 value = "number" 的情况
    const y = KeyCode[x.toString().toUpperCase() as any as number];
    if (y === undefined) {
        return undefined;
    }

    // 两重检查都过了，才能说明是正确的
    // 并且此时 y 是 value 的规范值
    return y as KeyMapperValue;
}

/**
 * 判断给定的 Mapper 是否为 KeyMapper 类型，或使之转变为规范的 KeyMapper 类型
 * @param mapper 要判断的值
 * @returns 如果给定的值满足 KeyMapper 类型条件则返回 KeyMapper，否则返回 undefined
 */
export function asKeyMapper(mapper: MapperConfig): KeyMapper | undefined {
    // 基本检查
    if (mapper.name.toLowerCase() !== "keymapper") {
        return undefined;
    }

    // 名称规范化
    mapper.name = "KeyMapper";

    // rule object 恢复
    if (typeof mapper.rule !== "object" || mapper.rule === null) {
        mapper.rule = {};
    }

    // rule 中的值的检查
    const keys = Object.keys(mapper.rule);
    for (const key of keys) {
        // rule value 类型检查
        const value = mapper.rule[key];

        // 1. value 是 string 类型
        if (typeof value === "string") {
            // 尝试转换（实际也是检查）
            const kmv = asKeyMapperValue(value);

            // 转换失败则删除
            if (kmv === undefined) {
                delete mapper.rule[key];
                continue;
            }

            // 转换成功则转换为数组
            mapper.rule[key] = [kmv];
        }
        // 2. value 是 array 类型
        else if (Array.isArray(value)) {
            // 逐个判断并进行转换
            for (let i = 0; i < value.length; i++) {
                // 尝试转换（实际也是检查）
                const kmv = asKeyMapperValue(value[i]);

                // 转换失败则删除
                if (kmv === undefined) {
                    value.splice(i, 1);
                    continue;
                }

                // 转换成功则设置
                value[i] = kmv;
            }

            // 清除空值
            if (value.length === 0) {
                delete mapper.rule[key];
            }
        }
        // 3. 其他，直接删除
        else {
            delete mapper.rule[key];
        }
    }

    // 完成检查并规范化
    return mapper as KeyMapper;
}
